################################################################################
# BAREFOOT NETWORKS CONFIDENTIAL & PROPRIETARY
#
# Copyright (c) 2018-2019 Barefoot Networks, Inc.

# All Rights Reserved.
#
# NOTICE: All information contained herein is, and remains the property of
# Barefoot Networks, Inc. and its suppliers, if any. The intellectual and
# technical concepts contained herein are proprietary to Barefoot Networks,
# Inc.
# and its suppliers and may be covered by U.S. and Foreign Patents, patents in
# process, and are protected by trade secret or copyright law.
# Dissemination of this information or reproduction of this material is
# strictly forbidden unless prior written permission is obtained from
# Barefoot Networks, Inc.
#
# No warranty, explicit or implicit is provided, unless granted under a
# written agreement with Barefoot Networks, Inc.
#
# Milad Sharif (msharif@barefootnetworks.com)
#
###############################################################################

import logging

import ptf.testutils as testutils
from bfruntime_base_tests import BfRuntimeTest
import bfrt_grpc.bfruntime_pb2 as bfruntime_pb2

logger = logging.getLogger('Test')
logger.addHandler(logging.StreamHandler())

class CounterTest(BfRuntimeTest):
    def runTest(self):
        ig_port = 1
        eg_port = 2
        smac = '11:33:55:77:99:00'
        smac_mask = 'ff:ff:ff:ff:ff:ff'
        dmac = '00:11:22:33:44:55'

        pkt = testutils.simple_tcp_packet(eth_dst=dmac, eth_src=smac)
        exp_pkt = pkt

        target = self.Target(device_id=0, pipe_id=0xffff)
        self.insert_table_entry(
            target,
            'SwitchIngress.forward',
            [self.KeyField('hdr.ethernet.src_addr', self.mac_to_bytes(smac),
                self.mac_to_bytes(smac_mask)),
                self.KeyField('$MATCH_PRIORITY', '\x00\x00\x00\x00')],
            'SwitchIngress.hit',
            [self.DataField('port', '\x00\x02'),
	     self.DataField('$COUNTER_SPEC_BYTES', '\x00'*8),
	     self.DataField('$COUNTER_SPEC_PKTS', '\x00'*8)])

	# Default packet size is 100 bytes and model adds 4 bytes of CRC
	pkt_size = 100 + 4
        num_pkts = 2;
	num_bytes = num_pkts * pkt_size

        logger.info("Sending packet on port %d", ig_port)
        for i in range(0,num_pkts):
            testutils.send_packet(self, ig_port, str(pkt))
            testutils.verify_packets(self, exp_pkt, [eg_port])

        logger.info("Expecting packet on port %d", eg_port)

        resp = self.get_table_entry(target,
            'SwitchIngress.forward',
            [self.KeyField('hdr.ethernet.src_addr', self.mac_to_bytes(smac),
                self.mac_to_bytes(smac_mask)),
                self.KeyField('$MATCH_PRIORITY', '\x00\x00\x00\x00')],
            {"from_hw":True},
            'SwitchIngress.hit',
            ["$COUNTER_SPEC_BYTES", "$COUNTER_SPEC_PKTS"])

	field_dict = {}
	pkts_field_id = self.get_data_field("SwitchIngress.forward", "SwitchIngress.hit", "$COUNTER_SPEC_PKTS")
	bytes_field_id = self.get_data_field("SwitchIngress.forward", "SwitchIngress.hit", "$COUNTER_SPEC_BYTES")
	field_dict[pkts_field_id] = 0
	field_dict[bytes_field_id] = 0

        # parse resp to get the counter
        self.parseGetResponse(resp, field_dict)
        recv_pkts = ''.join(x.encode('hex') for x in str(field_dict[pkts_field_id]))
	recv_pkts = int(recv_pkts, 16)
        recv_bytes = ''.join(x.encode('hex') for x in str(field_dict[bytes_field_id]))
	recv_bytes = int(recv_bytes, 16)

        if (num_pkts != recv_pkts):
            logger.error("Error! packets sent = %s received count = %s", str(num_pkts), str(recv_pkts))
	    assert 0;

        if (num_bytes != recv_bytes):
            logger.error("Error! bytes sent = %s received count = %s", str(num_bytes), str(recv_bytes))
	    assert 0;

        self.delete_table_entry(
            target,
            'SwitchIngress.forward',
            [self.KeyField('hdr.ethernet.src_addr', self.mac_to_bytes(smac),
                self.mac_to_bytes(smac_mask)),
                self.KeyField('$MATCH_PRIORITY', '\x00\x00\x00\x00')])

        logger.info("Sending packet on port %d", ig_port)
        testutils.send_packet(self, ig_port, str(pkt))

        logger.info("Packet is expected to get dropped.")
        testutils.verify_no_other_packets(self)

